﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace FundHelper.Model
{
    public abstract class IndicatorResult(DateTime dateTime, double value)
    {
        public DateTime DateTime=> dateTime;
        public virtual double Value=>value;
    }


    [AttributeUsage(AttributeTargets.Property)]
    public class IndicatorNameAttribute : Attribute
    {
        public string OutName { get; }
        public IndicatorNameAttribute(string name)
        {
            OutName = name;
        }
    }
    public  static partial class Indicator
    {
        public static int ConvertAF(this double value, string name)
        {
            double[] afs = [-10.06f, -3.81f, -1.83f, -0.45f, 0.70f, 2.01f, 3.92f, 10.63f];
            if (AFResult.AF5Dic.ContainsKey(name))
            {
                afs = AFResult.AF5Dic[name];
            }
            else
            {
                if (name.ToUpper().Contains("AF5MIN"))
                    afs = [-11f, -4.5f, -2.75f, -1.75f, -0.85f, -0.15f, 0.75f, 3.5f];
                if (name.ToUpper().Contains("AF5MAX"))
                    afs = [-3.5f, -0.6f, 0, 2f, 0.9f, 1.5f, 2.75f, 4.5f, 10.5f];
            }
            for (int i = 0; i < 8; i++)
            {
                if (value < afs[i])
                    return i == 0 ? -99 : i - 1;
            }
            return 99;
        }
        public static double CalculateEMA(List<double> prices, int period)
        {
            if (prices.Count < period)
                throw new ArgumentException("Not enough data points for the specified EMA period.");
            double ema = prices.Take(period).Average(); // 使用简单平均作为初始值

            for (int i = period; i < prices.Count; i++)
            {
                double t1 = 2f / (period + 1);
                double t2 = 1f - t1;
                ema = prices[i] * t1 + ema * t2;
            }
            return ema;
        }

        public static IEnumerable<SmaResult> GetSMAResult(this IEnumerable<(DateTime date, double price)> list, int period,int m=1)
        {
            var tuples = list.ToList();
            if (tuples.Count < period)
                throw new ArgumentException("Not enough data points for the specified SMA period.");
            var smaArry = new SmaResult[tuples.Count - period];
            var temp = tuples.OrderBy(a => a.date).ToList();
            double sma = temp.Take(period).Select(a => a.price).Average(); // 使用简单平均作为初始值

            for (int i = period; i < temp.Count; i++)
            {
                double t1 = (double)m / period;
                double t2 = 1f - t1;
                sma = temp[i].price * t1 + sma * t2;
                smaArry[i - period] = new SmaResult(temp[i].date, sma);
            }
            return smaArry.AsEnumerable();
        }
    }
    public interface ICanToTuple
    {      
        public (DateTime dateTime, double value) ToTuple();
        public Quote ToQuote();

    }
    /// <summary>
    /// 统计学五值
    /// </summary>
    /// <param name="Max">最大</param>
    /// <param name="Min">最小</param>
    /// <param name="Mid">中位数</param>
    /// <param name="Variance">方差</param>
    /// <param name="Mean">平均值</param>
    public record Statistic<T>(T Max, T Min, T Mid, double Variance, double Mean) where T:INumber<T>
    {
        public void Deconstruct(out T max, out T min, out T mid, out double variance, out double mean)
        {
            max = Max;
            min = Min;
            mid = Mid;
            variance = Variance;
            mean = Mean;
        }
        /// <summary>
        /// min,mid,max,mean,variance"
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return $"{Min},{Mid},{Max},{Mean},{Variance}";
        }
    }
    /// <summary>
    /// 数据提取描述
    /// </summary>
    /// <param name="period"></param>
    /// <param name="isStatitic"></param>
    public record ExtractionSetting(int[] period,bool isStatitic= false)
    {
        public int[] LagDay { get; set; } = [0];
        public ExtractionSetting(int[] period, int[] LagDay,bool isStatitic= false):this(period,isStatitic)
        {
            this.LagDay = LagDay ;
        }
    }
}
